# coding = utf-8
# Author: 柚一
import logging

import allure
import jsonpath
import pymysql
import requests
from deepdiff import DeepDiff
from pymysql import cursors

from core.globalContext import g_context
# pip install requests-toolbelt
from requests_toolbelt.multipart import MultipartEncoder
gc = g_context()


class Keywords:
    @allure.step("发送POST请求")
    def request_post(self, **kwargs):
        response = requests.post(**kwargs)
        # 返回结果设置全局变量去 current_response名字随意取  response返回结果
        gc.set_dict("current_response", response)
        return response

    @allure.step('发送post请求--form_data表单请求')
    def request_post_form_data(self, **kwargs):
        url = kwargs.get("URL", None)
        params = kwargs.get("PARAMS", None)
        data = kwargs.get("DATA", None)
        headers = kwargs.get("HEADERS", None)
        request_data = {
            "url": url,
            'params': params,
            'data': data,
            'headers': headers
        }
        response = self.request_post(**request_data)
        print("返回结果", response.json())
        return response

    @allure.step('发送post请求--form_json请求')
    def request_post_row_json(self, **kwargs):
        url = kwargs.get("URL", None)
        params = kwargs.get("PARAMS", None)
        data = kwargs.get("DATA", None)
        headers = kwargs.get("HEADERS", None)
        request_data = {
            "url": url,
            'params': params,
            'json': data,
            'headers': headers
        }
        response = self.request_post(**request_data)
        print("返回结果", response.json())
        return response

    @allure.step('发送post请求--文件上传')
    def request_post_form_urlencoded(self, **kwargs):
        url = kwargs.get("URL", None)
        file_path = kwargs.get("FILES", None)
        file = {"file": open(file_path, "rb")}
        params = kwargs.get("PARAMS", None)
        data = kwargs.get("DATA", None)
        headers = kwargs.get("HEADERS", None)
        request_data = {
            "url": url,
            "files": file,
            'params': params,
            'json': data,
            'headers': headers
        }
        response = self.request_post(**request_data)
        print("返回结果", response.json())
        return response

    @allure.step("发送GET请求")
    def request_get(self, **kwargs):
        url = kwargs.get("URL", None)
        params = kwargs.get("PARAMS", None)
        headers = kwargs.get("HEADERS", None)
        request_data = {
            "url": url,
            'params': params,
            'headers': headers
        }
        response = requests.get(**request_data)
        gc.set_dict("current_response", response)
        return response

    @allure.step("发送patch请求")
    def request_patch(self, **kwargs):
        url = kwargs.get("url", None)
        headers = kwargs.get("headers", None)
        request_data = {
            "url": url,
            'headers': headers
        }
        response = requests.patch(**request_data)
        gc.set_dict("current_response", response)
        return response

    @allure.step("发送PUT请求")
    def request_put(self, **kwargs):
        response = requests.put(**kwargs)
        gc.set_dict("current_response", response)
        return response

    @allure.step("发送DELETE请求")
    def request_delete(self, **kwargs):
        response = requests.delete(**kwargs)
        gc.set_dict("current_response", response)
        return response

    @allure.step("通过JSONPATH提取返回数据")
    def ex_jsonData(self, **kwargs):
        EXPRESSION = kwargs.get("EXVALUE", None)  # $..token/$.msg
        INDEX = kwargs.get("INDEX", None)  # 0
        if INDEX is None:
            INDEX = 0
        try:
            # 获得返回结果
            response = gc.get_dict("current_response").json()
        except Exception as e:
            logging.error("===获得结果失败=======")
            raise e
        ex_data = jsonpath.jsonpath(response, EXPRESSION)[INDEX]
        gc.set_dict(kwargs["VARNAME"], ex_data)
        return ex_data

    @allure.step("提取数据库数据并存储")
    def ex_mysqlData(self, **kwargs):
        # 初始化一个字典config，查询结果以字典形式返回
        config = {"cursorclass": cursors.DictCursor}
        # 数据库连接信息  从context.yaml文件拿出来
        db_config = g_context().get_dict("_database")[kwargs['数据库']]
        config.update(db_config)
        # 连接数据库信息
        con = pymysql.connect(**config)
        cur = con.cursor()
        cur.execute(kwargs["SQL"])
        rs = cur.fetchall() # [{'xx1':'value1'},{'xx2':'value2'}]
        cur.close()
        con.close()

        var_names = kwargs['引用变量'].split(",") # ['xx1','xx2']
        result = {}
        for i, data in enumerate(rs, start=1):
            # 循环引用变量中的名称
            for j, value in enumerate(var_names):
                result[f"{var_names[j]}_{i}"] = data.get(var_names[j]) # {'xx_1':value1}
        g_context().set_by_dict(result)

    @allure.step("文本断言")
    def assert_text_comparators(self, **kwargs):
        comparators = {
            '>': lambda a, b: a > b,
            '<': lambda a, b: a < b,
            '==': lambda a, b: a == b,
            '>=': lambda a, b: a >= b,
            '<=': lambda a, b: a <= b,
            '!=': lambda a, b: a != b,
        }
        message = kwargs.get("message", None)
        # == >= <= != 断言数字 中文  就需要预期结果和实际结果去进行对比
        if kwargs["OP_STR"] not in comparators:
            raise ValueError(f"没有该操作方式:{kwargs['OP_STR']}")
        if not comparators[kwargs["OP_STR"]](kwargs['VALUES'], kwargs['EXPECTED']):
            if message:
                raise AssertionError(message)
            else:
                raise AssertionError(f"{kwargs['VALUES']} {kwargs['OP_STR']} {kwargs['EXPECTED']}", '断言失败')

    @allure.step("全量断言")
    def assert_json_DeepDiff(self, **kwargs):
        try:
            json1 = gc.get_dict("current_response").json()  # 实际结果
            # json1=kwargs["json1"]#实际结果
            json2 = kwargs["json2"]  # 预期结果

            exclude_paths = kwargs.get("过滤字段", True)
            ignore_order = kwargs.get("忽略顺序", True)
            ignore_string_case = kwargs.get("忽略大小写", True)

            screen_data = {"exclude_paths": exclude_paths, "ignore_order": ignore_order,
                           "ignore_string_case": ignore_string_case}

            diff = DeepDiff(json1, json2, **screen_data)
        except Exception as e:
            assert False, f"全量断言失败，代码报错{e}"
        assert not diff, f"全量断言失败:{diff}"

    @allure.step("数据查询结果")
    def assert_db_exist(self, **kwargs):
        RESDB = kwargs.get('RESDB', None)
        if RESDB == '':
            raise AssertionError(f"数据库返回为空","断言失败")